package de.arndt_panzer.bensgallery;

import java.io.File;
import java.io.IOException;

import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;

public class SnappyCamActivity extends BensGalleryActivityBase implements
		SurfaceHolder.Callback {

	final static String TAG = SnappyCamActivity.class.getSimpleName();

	Long mLastCamKeyDownTime;
	Camera mCam;
	SurfaceHolder mHolder;
	SurfaceView mCamPreview;
	MediaRecorder mMediaRecorder = null;
	ImageView mImageViewState;
	ImageView mImageViewThumb;
	File mLastRecorded;
	ImageButton mImageButtonPicture;
	ImageButton mImageButtonRecord;
	ImageButton mImageButtonStop;

	@Override
	public boolean handleMessage(Message msg) {
		return false;
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_snappycam);

		mCamPreview = (SurfaceView) findViewById(R.id.surfaceView);
		mImageViewState = (ImageView) findViewById(R.id.imageView_state);
		mImageViewThumb = (ImageView) findViewById(R.id.imageView_thumb);
		mImageButtonPicture = (ImageButton) findViewById(R.id.imageButton_takePicture);
		mImageButtonRecord = (ImageButton) findViewById(R.id.imageButton_record);
		mImageButtonStop = (ImageButton) findViewById(R.id.imageButton_stop);

		mImageViewState.setVisibility(View.GONE);
		mImageViewThumb.setVisibility(View.GONE);
		mImageButtonStop.setVisibility(View.INVISIBLE);
		mImageButtonPicture.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				takePicture();
			}
		});
		mImageButtonRecord.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				startVideoRecord();
			}
		});
		mImageButtonStop.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				stopVideoRecord();
			}
		});
		mImageViewThumb.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				finish();
			}
		});
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		mCam = null;
	}

	@Override
	protected void onPause() {
		super.onPause();
		stopVideoRecord();
		try {
			mCam.stopPreview();
		} catch (Exception e) {
			Log.d(TAG, "onPause(): " + e.getMessage(), e);
		}
	}

	@Override
	protected void onRestart() {
		super.onRestart();
	}

	@Override
	protected void onResume() {
		super.onResume();
		try {
			mCam.startPreview();
		} catch (Exception e) {
			Log.d(TAG, "onPause(): " + e.getMessage(), e);
		}
	}

	@Override
	protected void onStart() {
		super.onStart();

		try {
			mCam = Camera.open();
		} catch (Exception e) {
			Toast.makeText(this, "Die Kamera ist nicht verfügbar :-(",
					Toast.LENGTH_LONG).show();
			finish();
			return;
		}

		if (mCam != null) {
			mHolder = mCamPreview.getHolder();
			mHolder.addCallback(this);
		} else
			finish();
	}

	@Override
	protected void onStop() {
		super.onStop();
		releaseMediaRecorder();
		mCam.release();
	}

	boolean mMediaVideoStopped = false;

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {

		switch (keyCode) {
		case KeyEvent.KEYCODE_CAMERA:
			if (mLastCamKeyDownTime == null) {
				// first call of keyDown
				mLastCamKeyDownTime = System.currentTimeMillis();
				mMediaVideoStopped = stopVideoRecord();
			}
			break;

		default:
			return super.onKeyDown(keyCode, event);
		}
		return true;
	}

	private boolean stopVideoRecord() {
		// stop video recording if active
		if (mMediaRecorder != null) {
			mImageViewState.setVisibility(View.GONE);
			try {
				mMediaRecorder.stop();
				setThumbnail(mLastRecorded);
			} catch (IllegalStateException e) {
				Log.d(TAG, e.getMessage(), e);
			}
			releaseMediaRecorder();
			mImageButtonPicture.setVisibility(View.VISIBLE);
			mImageButtonRecord.setVisibility(View.VISIBLE);
			mImageButtonStop.setVisibility(View.INVISIBLE);
			return true;
		}
		return false;
	}

	@Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {

		switch (keyCode) {
		case KeyEvent.KEYCODE_CAMERA:
			if (mLastCamKeyDownTime == null || mMediaVideoStopped) {
				// do nothing
				mMediaVideoStopped = false;

			} else if (System.currentTimeMillis() - mLastCamKeyDownTime <= 1000) {
				// take a picture
				takePicture();
			} else {
				// recording a video
				startVideoRecord();
			}
			mLastCamKeyDownTime = null;
			break;

		default:
			return super.onKeyUp(keyCode, event);

		}
		return true;
	}

	private boolean takePicture() {
		if (mCam != null && mMediaRecorder == null) {
			BitmapHelper.JpegStoreCallback jpeg = new BitmapHelper.JpegStoreCallback(
					this) {

				@Override
				public void onPictureTaken(byte[] data, Camera camera) {
					// process the picture data
					super.onPictureTaken(data, camera);

					mImageButtonPicture.setVisibility(View.VISIBLE);
					mImageButtonRecord.setVisibility(View.VISIBLE);

					// set the local thumb image
					mLastRecorded = getPictureFile();
					setThumbnail(mLastRecorded);
				}
			};

			mImageButtonPicture.setVisibility(View.INVISIBLE);
			mImageButtonRecord.setVisibility(View.INVISIBLE);
			// take a picture
			mCam.takePicture(null, null, jpeg);
			return true;
		}
		return false;
	}

	private boolean startVideoRecord() {
		if (mCam != null) {
			if (prepareVideoRecorder()) {
				try {
					mMediaRecorder.start();
					mImageViewState.setVisibility(View.VISIBLE);
					mImageButtonPicture.setVisibility(View.INVISIBLE);
					mImageButtonRecord.setVisibility(View.INVISIBLE);
					mImageButtonStop.setVisibility(View.VISIBLE);
					return true;
				} catch (Exception e) {
					Log.d(TAG, e.getMessage(), e);
					releaseMediaRecorder();
				}
			}
		}
		return false;
	}

	private void setThumbnail(File mediaFile) {
		if (mediaFile != null && BitmapHelper.isSupportedMedia(mediaFile)) {
			BitmapWorkerTask task = new BitmapWorkerTask();
			task.execute(new BitmapWorkerParameter(mediaFile.getAbsolutePath(),
					mImageViewThumb, 160, 120, false));
			mImageViewThumb.setVisibility(View.VISIBLE);
		}
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// surface dosn't exists yet
		if (mHolder != null && mHolder.getSurface() != null) {
			// stop preview
			try {
				mCam.stopPreview();
			} catch (Exception e) {
				Log.d(TAG, "surfaceChanged(): " + e.getMessage(), e);
			}
			// remove callback
			mHolder.removeCallback(this);
		}

		// initialize holder and callback
		mHolder = holder;
		mHolder.addCallback(this);
		try {
			mCam.setPreviewDisplay(mHolder);
			mCam.startPreview();
		} catch (IOException e) {
			Toast.makeText(this, "Kameravorschau lässt sich nicht öffnen :-(",
					Toast.LENGTH_LONG).show();
			Log.d(TAG, "surfaceChanged(): " + e.getMessage(), e);
		}

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// initialize holder and callback
		mHolder = holder;
		mHolder.addCallback(this);
		try {
			mCam.setPreviewDisplay(mHolder);
			mCam.startPreview();
		} catch (IOException e) {
			Toast.makeText(this, "Kameravorschau lässt sich nicht öffnen :-(",
					Toast.LENGTH_LONG).show();
			Log.d(TAG, "surfaceChanged(): " + e.getMessage(), e);
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		if (holder != null) {
			// stop preview
			try {
				mCam.stopPreview();
			} catch (Exception e) {
				Log.d(TAG, "surfaceChanged(): " + e.getMessage(), e);
			}
			// remove callback
			holder.removeCallback(this);
		}
		mHolder = null;
	}

	private boolean prepareVideoRecorder() {

		mCam.stopPreview();

		mMediaRecorder = new MediaRecorder();

		// Step 1: Unlock and set camera to MediaRecorder
		mCam.unlock();
		mMediaRecorder.setCamera(mCam);

		// Step 2: Set sources
		mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
		mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

		// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
		mMediaRecorder.setProfile(CamcorderProfile
				.get(CamcorderProfile.QUALITY_HIGH));

		// Step 4: Set output file
		mLastRecorded = BitmapHelper
				.getOutputMediaFile(BitmapHelper.MEDIA_TYPE_VIDEO);
		mMediaRecorder.setOutputFile(mLastRecorded.toString());

		// Step 5: Set the preview output
		mMediaRecorder.setPreviewDisplay(mHolder.getSurface());

		// Step 6: Prepare configured MediaRecorder
		try {
			mMediaRecorder.prepare();
		} catch (IllegalStateException e) {
			Log.d(TAG,
					"IllegalStateException preparing MediaRecorder: "
							+ e.getMessage());
			releaseMediaRecorder();
			return false;
		} catch (IOException e) {
			Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
			releaseMediaRecorder();
			return false;
		}
		return true;
	}

	private void releaseMediaRecorder() {
		if (mMediaRecorder != null) {
			mMediaRecorder.reset(); // clear recorder configuration
			mMediaRecorder.release(); // release the recorder object
			mMediaRecorder = null;
			mCam.lock(); // lock camera for later use
		}
	}

}
